using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using Activa.CoolStorage;
using CodeStory.Core.ObjectEntity;
using CodeStory.Core.Services;
using CodeStory.Core.Providers;
using System.Collections;
using System.Web.UI.HtmlControls;
using System.Collections.Specialized;

namespace CodeStory.Core.UI
{
	/// <summary>
	/// 
	/// </summary>
	public class PageHierarchyBuilder : IRefreshable
	{
		private Control container;
		private Page page;
		private PageObject pageObject;

		private bool _editMode = false;


		public const string AppRelativeTemplateSourceDirectoryDataKey = "CodeStory.TempAppRelativeTemplateSourceDirectory";
		public string TempAppRelativeTemplateSourceDirectory {
			set { HttpContext.Current.Items[AppRelativeTemplateSourceDirectoryDataKey] = value; }
		}
		/// <summary>
		/// The container control of the build "page".
		/// </summary>
		public Control Container {
			get { return container; }
			set { container = value; }
		}
		/// <summary>
		/// The Page object.
		/// </summary>
		public PageObject PageObject {
			get { return pageObject; }
			set { pageObject = value; }
		}
		public Page Page {
			get { return page; }
			set { page = value; }
		}
		private List<Control> userControlsInPage;
		/// <summary>
		/// Get the "portlet" controls list.
		/// </summary>
		public List<Control> UserControlsInPage {
			get {
				if (userControlsInPage == null) {
					userControlsInPage = new List<Control>();
				}
				return userControlsInPage;
			}
		}
		private UserCookie userCookie = null;
		/// <summary>
		/// Get the UserCookie object of the current session.
		/// </summary>
		public UserCookie UserCookie {
			get {
				if (userCookie == null) {
					userCookie = new UserCookie(HttpContext.Current);
				}
				return userCookie;
			}
		}

		/// <summary>
		/// Get the current skin name of the site.
		/// </summary>
		public string SkinName {
			get {
				string name = UserCookie.SkinName;
				if (string.IsNullOrEmpty(name)) {
					name = CodeStoryConfig.DefaultSkinName;
				}
				return name;
			}
		}
		/// <summary>
		/// Get or set whether the page was in an edit mode.
		/// </summary>
		public bool EditMode {
			get { return _editMode; }
			set { _editMode = value; }
		}

		public PageHierarchyBuilder(Page page, PageObject pageObject,Control container) {
			this.Page = page;
			this.PageObject = pageObject;
			this.container = container;
			//container.ID = "CSContainer";
		}

		public PageHierarchyBuilder() {

		}

		/// <summary>
		/// This method was used to create the page's controls hierarchy.
		/// </summary>
		public void InitializePage() {
			LoadSettings(pageObject.PageSetting);
			CreatePageControlHierarchy();
			if (!string.IsNullOrEmpty(PageObject.PageSetting)) {
				LoadSettings(PageObject.PageSetting);
			}
			ApplyStyleSheets();
		}

		/// <summary>
		/// 
		/// </summary>
		private void ApplyStyleSheets() {
			//throw new Exception("The method or operation is not implemented.");
			string list = CodeStorySiteSetting.Current.StyleSheetListString;
			if (string.IsNullOrEmpty(list)) return;
			string[] stylesheets = list.Split('|');
			foreach (string style in stylesheets) {
				//HtmlGenericControl c = new HtmlGenericControl("link");
				HtmlLink c = new HtmlLink();
				string url = BuildStyleSheetPath(style);
				if (string.IsNullOrEmpty(url)) continue;
				c.Attributes.Add("type","text/css");
				c.Attributes.Add("rel","stylesheet");
				c.Href = url;
				Page.Header.Controls.Add(c);
			}
		}

		/// <summary>
		/// Builds the style sheet path.
		/// </summary>
		/// <param name="path">The path.</param>
		/// <returns></returns>
		private string BuildStyleSheetPath(string path) {
			string controlPath = FileUtilityService.Combine("Skins", SkinName, "CSS", path);
			string fileName = Page.Server.MapPath(controlPath);
			if (!FileUtilityService.TestFileExists(fileName)) {
				controlPath = FileUtilityService.Combine("Skins", "default", "CSS", path);
				fileName = Page.Server.MapPath(controlPath);
				if (!FileUtilityService.TestFileExists(fileName)) {
					return string.Empty;
				}
			}
			return controlPath;
		}

		#region Create Page Control Hierarchy
		/// <summary>
		/// Creates the page control hierarchy.
		/// </summary>
		private void CreatePageControlHierarchy() {
			string layout = PageObject.LayoutObject.LayouTemplate;
			Control layoutTemplateControl = Page.ParseControl(layout);

			List<string> list = GeneratePaneNameList(layoutTemplateControl);

			Container.Controls.Add(layoutTemplateControl);

			CSList<PagePortletObject> portletList = PageObject.PagePortlets.OrderedBy("InsertOrder");
			foreach (PagePortletObject obj in portletList) {
				Control con = layoutTemplateControl.FindControl(obj.PaneName);
				if (con == null) {
					con = Container;
				}
				PortletObject portlet = obj.PortletObject;
				Control control = LoadPortletControl(portlet);
				UserControlsInPage.Add(control);
				object setting = GetPagePortletSetting(obj.PagePortletID);
				if (setting != null) {
					IPortlet m = control as IPortlet;
					if (m != null) {
						m.LoadSetting(setting);
					}
				}
				if (control is Portlet) {
					Portlet p = (Portlet)control;
					p.EditMode = EditMode;
					if (p.ShowContainer) {
						control = ApplyPortletSkin(control, p.ContainerName);
					}
					if (control is PortletContainer) {
						PortletContainer c = (PortletContainer)control;
						c.TitleBarVisible = p.ShowTitle;
						if (p.ShowTitle) {
							string title = p.Title;
							if (string.IsNullOrEmpty(title)) {
								title = portlet.PortletName; 
							}
							if (string.IsNullOrEmpty(title)) {
								c.TitleBarVisible = false;
							} else {
								c.PortletTitle = title;
							}
						}
					}
				}
				if (EditMode) {
					PortletEditMenu menu = new PortletEditMenu(obj,list,this);
					if (control is PortletContainer) {
						Control c = control.FindControl("Portlet");
						c.Controls.AddAt(0,menu);
					} else {
						control.Controls.AddAt(0, menu);
					}
				}
				AddControlToContainer(con, control);
			}
		}

		/// <summary>
		/// Generates the pane name list.
		/// </summary>
		/// <param name="c">The c.</param>
		/// <returns></returns>
		public static List<string> GeneratePaneNameList(Control c) {
			List<string> list = new List<string>(8);
			foreach (Control pc in c.Controls) {
				if (c is LiteralControl) continue;
				if (string.IsNullOrEmpty(pc.ClientID)) continue;
				list.Add(pc.ClientID);
			}
			return list;
		}

		/// <summary>
		/// Loads the portlet control.
		/// </summary>
		/// <param name="portlet">The portlet.</param>
		/// <returns></returns>
		public Control LoadPortletControl(PortletObject portlet) {
			string path = portlet.PortletPath;
			
			string controlPath = BuildControlPath(path);
			TempAppRelativeTemplateSourceDirectory = controlPath.Substring(0, controlPath.Length - path.Length);
			Control control = Page.LoadControl(controlPath);
			if (control is PartialCachingControl) {
				control = ((PartialCachingControl)control).CachedControl;
			}
			return control;
		}

		/// <summary>
		/// Adds the control to container.
		/// </summary>
		/// <param name="con">The con.</param>
		/// <param name="control">The control.</param>
		private void AddControlToContainer(Control con, Control control) {
			SetControlID(control);
			if (con != null) {
				con.Controls.Add(control);
			}
		}

		private int _NameIndex = 0;

		/// <summary>
		/// Sets the control ID.
		/// </summary>
		/// <param name="control">The control.</param>
		private void SetControlID(Control control) {
			control.ID = string.Format("CS{0}", _NameIndex);
			_NameIndex++;
		}


		/// <summary>
		/// Applies the portlet skin.
		/// </summary>
		/// <param name="control">The control.</param>
		/// <param name="name">The name.</param>
		/// <returns></returns>
		private Control ApplyPortletSkin(Control control, string name) {
			string skinName = name;
			if (string.IsNullOrEmpty(skinName)) {
				skinName = CodeStorySiteSetting.Current.DefaultContainerName;
			}
			if (skinName.Equals("{none}", StringComparison.OrdinalIgnoreCase)) {
				return control;
			}
			string templateFilePath = PortletTemplateCache.Instance[skinName].TemplateFilePath;

			templateFilePath = BuildContainerPath(templateFilePath);


			Control c = Page.LoadControl(templateFilePath);
			if (c == null) {
				throw new Exception("");
			}
			Control pl = c.FindControl("Portlet");
			pl.Controls.Add(control);
			((Portlet)control).PortletContainer = (PortletContainer)c;
			return c;
		}


		/// <summary>
		/// Builds the container path.
		/// </summary>
		/// <param name="path">The path.</param>
		/// <returns></returns>
		private string BuildContainerPath(string path) {
			string controlPath = FileUtilityService.Combine("~\\Skins", SkinName, "Container", path);
			string fileName = Page.Server.MapPath(controlPath);
			if (!FileUtilityService.TestFileExists(fileName)) {
				controlPath = FileUtilityService.Combine("~\\Skins", "default", "Container", path);
				fileName = Page.Server.MapPath(controlPath);
				if (!FileUtilityService.TestFileExists(fileName)) {
					throw new Exception("The module must supported default skin!");
				}
			}
			return controlPath;
		}

		/// <summary>
		/// Builds the control path.
		/// </summary>
		/// <param name="path">The path.</param>
		/// <returns></returns>
		private string BuildControlPath(string path) {
			string controlPath = FileUtilityService.Combine("~\\Skins", SkinName, path);
			string fileName = Page.Server.MapPath(controlPath);
			if (!FileUtilityService.TestFileExists(fileName)) {
				controlPath = FileUtilityService.Combine("~\\Skins", "default", path);
				fileName = Page.Server.MapPath(controlPath);
				if (!FileUtilityService.TestFileExists(fileName)) {
					throw new Exception("The module must supported default skin!");
				}
			}
			return controlPath;
		}
		#endregion

		#region Settings

		IDictionary settingDictionary;

		public IDictionary LoadSettings(string setting) {
			settingDictionary = new Hashtable(8);
			if (string.IsNullOrEmpty(setting)) return settingDictionary;
			ObjectStateFormatter f = new ObjectStateFormatter();
			object obj = f.Deserialize(setting);
			settingDictionary = obj as IDictionary;
			return settingDictionary;
		}

		private object GetPagePortletSetting(Guid id) {
			if (settingDictionary != null) {
				if (settingDictionary.Contains(id)) {
					return settingDictionary[id];
				}
			}
			return null;
		}
		#endregion

		#region IRefreshable Members

		/// <summary>
		/// Refresh the state of the cached object.
		/// </summary>
		public void Refresh() {
			_NameIndex = 0;
			PageObject = PageObject.Read(PageObject.PageID);
			Container.Controls.Clear();
			InitializePage();
		}

		/// <summary>
		/// Refresh the state of the cached object.
		/// </summary>
		void IRefreshable.Refresh() {
			this.Refresh();
		}

		#endregion
	}
}